package dom.example.lucene.utils;

import bom.example.common.utils.ListUtils;
import bom.example.common.utils.PathUtils;
import com.alibaba.fastjson.JSON;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.apache.poi.ss.formula.functions.T;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Xiongx
 * @version 1.0
 * @date 2021/7/31 13:26
 * @since JDK 1.8
 *
 * 搜索工具类
 */
public class LuceneUtils extends Lucene {



    public static void indexSearch(String name) throws Exception{
        // 1. 创建分析器对象(Analyzer), 用于分词
        Analyzer analyzer = new StandardAnalyzer();

        // 2. 创建查询对象(Query)
        // 2.1 创建查询解析器对象
        // 参数一:默认的搜索域, 参数二:使用的分析器
        QueryParser queryParser = new QueryParser("title", analyzer);
        // 2.2 使用查询解析器对象, 实例化Query对象
        Query query = queryParser.parse("title:"+name);

        // 3. 创建索引库目录位置对象(Directory), 指定索引库位置
        Directory directory = FSDirectory.open(new File("C:\\Users\\xiong\\Desktop\\index"));

        // 4. 创建索引读取对象(IndexReader), 用于读取索引
        IndexReader indexReader = DirectoryReader.open(directory);

        // 5. 创建索引搜索对象(IndexSearcher), 用于执行索引
        IndexSearcher searcher = new IndexSearcher(indexReader);

        // 6. 使用IndexSearcher对象执行搜索, 返回搜索结果集TopDocs
        // 参数一:使用的查询对象, 参数二:指定要返回的搜索结果排序后的前n个
        TopDocs topDocs = searcher.search(query, 10);

        // 7. 处理结果集
        // 7.1 打印实际查询到的结果数量
        System.out.println("实际查询到的结果数量: " + topDocs.totalHits);
        // 7.2 获取搜索的结果数组
        // ScoreDoc中有文档的id及其评分
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            System.out.println("= = = = = = = = = = = = = = = = = = =");
            // 获取文档的id和评分
            int docId = scoreDoc.doc;
            float score = scoreDoc.score;
            System.out.println("文档id= " + docId + " , 评分= " + score);
            // 根据文档Id, 查询文档数据 -- 相当于关系数据库中根据主键Id查询数据
            Document doc = searcher.doc(docId);
            System.out.println("图书Id: " + doc.get("title"));
        }

        // 8. 关闭资源
        indexReader.close();
    }

    /**
     * lunce搜索
     * @param indexName 索引名称
     * @param field 属性名称
     * @param keyword 关键字
     * @param total 搜索的条数
     * @return
     * @throws Exception
     */
    public static List<Map<String, Object>> searchMapByKey(String indexName,String field,String keyword,Integer total) throws Exception{
        IndexSearcher indexSearcher=createIndexSearcher(indexName);
        Query query = new TermQuery(new Term(field, keyword));
        TopDocs topDocs = indexSearcher.search(query, 100);
        System.out.println(topDocs.totalHits);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        List<Document> documents=getDocumentByScore(scoreDocs,indexSearcher);
        List<Map<String, Object>> objectMaps=getDocumentArrayToMapArray(documents);
        return objectMaps;
    }

    /**
     * 模糊查询
     * @param indexName
     * @param field
     * @param keyword
     * @param toatl
     * @return
     * @throws Exception
     */
    public static List<Map<String, Object>> likeSearch(String indexName,String field,String keyword,Integer toatl) throws Exception{
        IndexSearcher indexSearcher=createIndexSearcher(indexName);
        FuzzyQuery fuzzyQuery=new FuzzyQuery(new Term(field,keyword));
        TopDocs topDocs = indexSearcher.search(fuzzyQuery, 100);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        List<Document> documents=getDocumentByScore(scoreDocs,indexSearcher);
        List<Map<String, Object>> objectMaps=getDocumentArrayToMapArray(documents);
        return objectMaps;
    }








    /**
     * luncene搜索
     * @param indexName 索引名称
     * @param field  属性
     * @param keyword  关键字
     * @param total  搜索条数
     * @return
     * @throws Exception
     */
    public static   List<Map<String, Object>> searchByKeyWord(String indexName,String field,String keyword,Integer total) throws Exception{
        IndexSearcher indexSearcher=createIndexSearcher(indexName);
        TopDocs topDocs=getQueryDoc(indexSearcher,keyword,field,total);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        List<Document> documents=getDocumentByScore(scoreDocs,indexSearcher);
        System.out.println(documents.size()+"size");
        List<Map<String, Object>> objectMaps=getDocumentArrayToMapArray(documents);
        return objectMaps;
    }

    /**
     *
     * @param indexName 索引名称
     * @param idKey 数据的主键key
     * @param maps 数据
     * @return
     * @throws Exception
     */
    public static void updateDocument(String indexName,String idKey,List<Map<String, Object>> maps) throws Exception{
        IndexWriter indexWriter=getIndexWriter(indexName);
        for (int i = 0; i < maps.size(); i++) {
            Map<String, Object> map=maps.get(i);
            String value=String.valueOf(map.get(idKey));
            Document document=createDocument(map);
            //执行的操作实际是先删除，后添加
            indexWriter.updateDocument(new Term(idKey,value),document);
        }
        indexWriter.close();
    }

    /**
     * lucene的删除
     * @param indexName
     * @param key
     * @param value
     * @throws Exception
     */
    public static void deleteDoucument(String indexName,String key,String value) throws Exception{
        IndexWriter indexWriter=getIndexWriter(indexName);
        indexWriter.deleteDocuments(new Term(key,value));
        indexWriter.close();
    }






    /**
     *    组合多个子查询
     *     Occur.SHOULD 或
     *     Occur.MUST 且
     *     Occur.MUST_NOT 且非
     *     Occur.FILTER 同MUST 但该字句不参与评分、
     */
    public static List<Map<String, Object>> searchConditionBuild(String indexName, String field_1, String keyword_1, String
            field_2, String keyword_2, Integer toatl) throws Exception{
        IndexSearcher indexSearcher=createIndexSearcher(indexName);
        FuzzyQuery fuzzyQuery_1=new FuzzyQuery(new Term(field_1,keyword_1));
        FuzzyQuery fuzzyQuery_2=new FuzzyQuery(new Term(field_2,keyword_2));

        BooleanQuery booleanQueryBuilder = new BooleanQuery();
        booleanQueryBuilder.add(fuzzyQuery_1, BooleanClause.Occur.SHOULD);
        booleanQueryBuilder.add(fuzzyQuery_2, BooleanClause.Occur.SHOULD);

        TopDocs topDocs = indexSearcher.search(booleanQueryBuilder, 100);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        List<Document> documents=getDocumentByScore(scoreDocs,indexSearcher);
        List<Map<String, Object>> objectMaps=getDocumentArrayToMapArray(documents);
        return objectMaps;
    }


    /**
     * 批量添加
     * @param indexName
     * @param objectMaps
     * @throws Exception
     */
    public static void addListDocumentByIndexName(String indexName,List<Map<String, Object>> objectMaps) throws Exception{
        List<Document> documents=listToDocument(objectMaps);
        IndexWriter indexWriter=getIndexWriter(indexName);
        for (int i = 0; i < documents.size(); i++) {
            Document document=documents.get(i);
            indexWriter.addDocument(document);
        }
        indexWriter.close();
    }

    /**
     * 添加数据通过索引名称，只添加单个
     * @param indexName
     * @param document
     * @throws Exception
     */
    public static void addDocumentByIndexName(String indexName, Document document) throws Exception{
        IndexWriter indexWriter=getIndexWriter(indexName);
        indexWriter.addDocument(document);
        indexWriter.close();
    }

    /**
     * 获取索引集合
     * @return
     */
    public static List<String> getIndexList(){
        File file=PathUtils.getPathByName(LuceneContants.INDEX_DICTORY);
        String[] strings=file.list();
        List<String> strings1=ListUtils.formartList(strings);
        return strings1;
    }

    public static <T> void addList(List<T> tList) throws Exception{
        if(tList==null && tList.size()==0){
            return;
        }
        T t=tList.get(0);
        Class<T> cls=(Class<T>) t.getClass();
        String indexName=t.getClass().getName();
        List<Map<String, Object>> objectMaps=objectsToMaps(tList);
        addListDocumentByIndexName(indexName,objectMaps);
    }


}
